﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

using Aphysoft.Vate.Graphics;

namespace Aphysoft.Vate
{
    public partial class Vate
    {
        #region Properties
        /// <summary>
        /// True if device has changed; otherwise, false.
        /// </summary>
        private bool mustApplyDeviceChanges = false;
        /// <summary>
        /// Graphics device manager, used for the graphics creation and holds the GraphicsDevice.
        /// </summary>
        private static GraphicsDeviceManager graphicsManager = null;
        /// <summary>
        /// Graphics device manager, used for the graphics creation and holds the GraphicsDevice.
        /// </summary>
        public static GraphicsDeviceManager GraphicsManager
        {
            get { return graphicsManager; }
        }
        private static GraphicsDevice graphicsDevice = null;
        /// <summary>
        /// Gets GraphicsDevice instance in current game graphics manager.
        /// </summary>
        public static GraphicsDevice Device
        {
            get { return graphicsDevice; }
        }
        /// <summary>
        /// Gets a value indicating whether the game screen in fullscreen mode.
        /// </summary>
        public static bool Fullscreen
        {
            get { return graphicsManager.IsFullScreen; }
        }
        /// <summary>
        /// Start Up screen resolution.
        /// </summary>
        private int startUpWidth = 1280, startUpHeight = 720;
        /// <summary>
        /// Start Up screen resolution: Width.
        /// </summary>
        public int StartUpWidth
        {
            get { return startUpWidth; }
            set { startUpWidth = value; }
        }
        /// <summary>
        /// Start Up screen resolution: Height.
        /// </summary>
        public int StartUpHeight
        {
            get { return startUpHeight; }
            set { startUpHeight = value; }
        }
        /// <summary>
        /// Start up aspect ratio.
        /// </summary>
        private ScreenRatio startUpAspectRatio = ScreenRatio.SixteenToNine;
        /// <summary>
        /// Start up aspect ratio.
        /// </summary>
        public ScreenRatio StartUpAspectRatio
        {
            get { return startUpAspectRatio; }
            set { startUpAspectRatio = value; }
        }
        /// <summary>
        /// Our screen resolution: Width and height of visible render area.
        /// </summary>
        private static int width, height;
        /// <summary>
        /// Our screen resolution: Width of visible render area.
        /// </summary>
        public static int Width
        {
            get { return width; }
            set { width = value; }
        }
        /// <summary>
        /// Our screen resolution: Height of visible render area.
        /// </summary>
        public static int Height
        {
            get { return height; }
            set { height = value; }
        }
        /// <summary>
        /// Aspect ratio of current resolution.
        /// </summary>
        private static ScreenRatio aspectRatio = ScreenRatio.SixteenToNine;
        /// <summary>
        /// Aspect ratio of current resolution.
        /// </summary>
        public static ScreenRatio AspectRatio
        {
            get { return aspectRatio; }
        }
        /// <summary>
        /// Screen definition size.
        /// </summary>
        private static DefinitionSize definition = DefinitionSize.HD;
        /// <summary>
        /// Screen definition size.
        /// </summary>
        public static DefinitionSize Definition
        {
            get { return definition; }
        }
        /// <summary>
        /// Default viewport.
        /// </summary>
        private static Viewport defaultViewport;
        /// <summary>
        /// Gets a reference to default viewport of the game.
        /// </summary>
        public static Viewport DefaultViewport
        {
            get { return defaultViewport; }
            set { defaultViewport = value; }
        }
        /// <summary>
        /// Gets current camera of current projector. Shortcut of BasePage.ProjectorManager.CurrentProjector.Camera.
        /// </summary>
        public static Camera CurrentCamera
        {
            get
            {
                if (ProjectorManager.Current.Length == 0)
                    return null;
                else
                    return ProjectorManager.CurrentProjector.Camera;
            }
        }
        /// <summary>
        /// Gets current projector. Shortcut of BasePage.ProjectorManager.CurrentProjector.
        /// </summary>
        public static Projector CurrentProjector
        {
            get { return ProjectorManager.CurrentProjector; }
        }
        /// <summary>
        /// Back buffer depth format.
        /// </summary>
        private DepthFormat backBufferDepthFormat = DepthFormat.Depth32;
        /// <summary>
        /// Back buffer depth format.
        /// </summary>
        public DepthFormat BackBufferDepthFormat
        {
            get { return backBufferDepthFormat; }
        }
        /// <summary>
        /// Global Alpha Sprite Batch.
        /// </summary>
        private static SpriteBatch globalAlphaSpriteBatch = null;
        /// <summary>
        /// Global Alpha Sprite Batch.
        /// </summary>
        public static SpriteBatch GlobalAlphaSpriteBatch
        {
            get { return globalAlphaSpriteBatch; }
            set { globalAlphaSpriteBatch = value; }
        }
        /// <summary>
        /// Global Additive Sprite Batch.
        /// </summary>
        private static SpriteBatch globalAdditiveSpriteBatch = null;
        /// <summary>
        /// Global Additive Sprite Batch.
        /// </summary>
        public static SpriteBatch GlobalAdditiveSpriteBatch
        {
            get { return globalAdditiveSpriteBatch; }
            set { globalAdditiveSpriteBatch = value; }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Graphics setup.
        /// </summary>
        private void GraphicsSetup()
        {
            // Set graphics manager
            graphicsManager = new GraphicsDeviceManager(this);

            // Set minimum requirements
            graphicsManager.MinimumPixelShaderProfile = ShaderProfile.PS_2_0;
            graphicsManager.MinimumVertexShaderProfile = ShaderProfile.VS_2_0;

            // Graphics manager device changes handler
            graphicsManager.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(GraphicsPrepareDevice);
            graphicsManager.DeviceReset += new EventHandler(GraphicsDeviceReset);

            Vate.SetGraphicsDevice(graphicsDevice);
#if DEBUG
            // Disable vertical retrace to get highest framerates possible for
            // testing performance.
            graphicsManager.SynchronizeWithVerticalRetrace = false;
#endif
            // Set depth format
            backBufferDepthFormat = graphicsManager.PreferredDepthStencilFormat;
        }
        /// <summary>
        /// Apply resolution change.
        /// </summary>
        private void ApplyResolutionChange()
        {
#if XBOX360
            // Xbox 360 graphics settings are fixed
            graphicsManager.IsFullScreen = true;
            graphicsManager.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            graphicsManager.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
#else
            // TODO: tergantung settings
            Window.AllowUserResizing = true;

            int resolutionWidth = StartUpWidth;
            int resolutionHeight = StartUpHeight;
            aspectRatio = StartUpAspectRatio;

            // Use current desktop resolution if autodetect is selected.
            if (resolutionWidth <= 0 || resolutionHeight <= 0)
            {
                resolutionWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
                resolutionHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            }

            // Windows
            graphicsManager.IsFullScreen = false;
            graphicsManager.PreferredBackBufferWidth = resolutionWidth;
            graphicsManager.PreferredBackBufferHeight = resolutionHeight;

            // Apply changes
            mustApplyDeviceChanges = true;
#endif
        }
        /// <summary>
        /// Raised when GraphicsDeviceManager is changing the GraphicsDevice settings (during reset or recreation
        /// of the GraphicsDevice).
        /// TODO: fix this.
        /// </summary>
        private void GraphicsPrepareDevice(object sender, PreparingDeviceSettingsEventArgs e)
        {
            if (Environment.OSVersion.Platform != PlatformID.Win32NT)
            {
                PresentationParameters presentParams = e.GraphicsDeviceInformation.PresentationParameters;

                presentParams.RenderTargetUsage = RenderTargetUsage.PlatformContents;
                if (graphicsManager.PreferredBackBufferHeight == 720)
                {
                    presentParams.MultiSampleType = MultiSampleType.FourSamples;
#if !DEBUG
                    presentParams.PresentationInterval = PresentInterval.One;
#endif
                }
                else
                {
                    presentParams.MultiSampleType = MultiSampleType.TwoSamples;
#if !DEBUG
                    presentParams.PresentationInterval = PresentInterval.Two;
#endif
                }
            }
        }
        /// <summary>
        /// Raised when GraphicsDeviceManager is reset.
        /// </summary>
        private void GraphicsDeviceReset(object sender, EventArgs e)
        {
            // Update master width and height
            width = graphicsManager.GraphicsDevice.Viewport.Width;
            height = graphicsManager.GraphicsDevice.Viewport.Height;

            // Update default projector
            defaultViewport = graphicsManager.GraphicsDevice.Viewport;

            // Update projectors
            ProjectorManager.DefaultProjector.Update();

            foreach (KeyValuePair<string, Projector> projectorEntry in ProjectorManager.Projectors)
            {
                string gameProjectorName = projectorEntry.Key;
                Projector gameProjector = projectorEntry.Value;

                gameProjector.Update();
            }

            SetGraphicsDevice(graphicsManager.GraphicsDevice);
#if DEBUG
            Debug.Write("GraphicsDevice Reset.");
#endif
        }
        /// <summary>
        /// Set graphics device used by the application. Internal use only.
        /// </summary>
        /// <param name="graphicsDevice"></param>
        public static void SetGraphicsDevice(GraphicsDevice graphicsDevice)
        {
            Vate.graphicsDevice = graphicsDevice;
        }
        #endregion
    }
}
